package secondriver.springsubway.example.auc;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import secondriver.springsubway.example.auc.annotation.PermissionIngore;
import secondriver.springsubway.example.auc.annotation.PermissionPoint;

public class PermissionInterceptor extends HandlerInterceptorAdapter {

	public static final String SUBJECT_KEY = "__subject_key__";

	private String subjectKey = SUBJECT_KEY;

	private NoPermissionHandler noPermissionHandler;

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		if (!(handler instanceof HandlerMethod)) {
			return super.preHandle(request, response, handler);
		}

		HandlerMethod handlerMethod = (HandlerMethod) handler;

		PermissionIngore permissionIngore = handlerMethod
				.getMethodAnnotation(PermissionIngore.class);

		if (null != permissionIngore && permissionIngore.value()) {
			return super.preHandle(request, response, handlerMethod);
		}

		Object value = request.getSession().getAttribute(subjectKey);

		Assert.notNull(value, this.getClass().getCanonicalName()
				+ " request attribute " + subjectKey
				+ " value must not be null.");
		Assert.isTrue(value instanceof Subject, value.getClass()
				.getCanonicalName() + " must be infance of " + Subject.class);

		Subject subject = (Subject) value;

		Object bean = handlerMethod.getBean();
		PermissionPoint classPermissionPoint = AnnotationUtils.findAnnotation(
				bean.getClass(), PermissionPoint.class);

		boolean isPermssion = false;
		if (null == classPermissionPoint
				|| subject.hasPermission(classPermissionPoint.value())) {
			PermissionPoint methodPermissionPoint = handlerMethod
					.getMethodAnnotation(PermissionPoint.class);
			isPermssion = null == methodPermissionPoint
					|| subject.hasPermission(methodPermissionPoint.value());
		}
		if (isPermssion) {
			return super.preHandle(request, response, handlerMethod);
		} else {
			if (null == noPermissionHandler) {
				noPermissionHandler = new DefaultNoPermissionHandler();
			}
			noPermissionHandler.handler(request, response);
			return false;
		}
	}

	public String getSubject() {
		return subjectKey;
	}

	public void setSubject(String subject) {
		this.subjectKey = subject;
	}

	public NoPermissionHandler getNoPermissionHandler() {
		return noPermissionHandler;
	}

	public void setNoPermissionHandler(NoPermissionHandler noPermissionHandler) {
		this.noPermissionHandler = noPermissionHandler;
	}

	class DefaultNoPermissionHandler implements NoPermissionHandler {

		@Override
		public void handler(HttpServletRequest request,
				HttpServletResponse response) throws IOException {
			response.setStatus(403);
			response.addHeader("Content-Type", "application/json;charset=UTF-8");
			response.setCharacterEncoding("UTF-8");
			PrintWriter write = response.getWriter();
			write.print("{\"msg\":\"Not Permission Access.\"}");
			write.flush();
			write.close();
		}
	}
}
